package org.example.judge_admin.controller;


import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.example.judge_admin.service.AuthService;
import org.example.judge_admin.service.SessionService;
import org.example.judge_admin.service.UserService;
import org.example.judge_common.annotation.AuthAnnotation;
import org.example.judge_common.entity.ResponseResult;
import org.example.judge_common.util.IdWorker;
import org.example.judge_common.util.MailClient;
import org.example.judge_common.util.MyUtils;
import org.example.judge_pojo.Auth;
import org.example.judge_pojo.Session;
import org.example.judge_pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@CrossOrigin
@RestController
@RequestMapping("/login")
@Slf4j
public class LoginController {


    @Autowired
    private UserController userController;
    @Qualifier("SessionServiceImpl")
    @Autowired
    private SessionService sessionService;

    @Autowired
    private IdWorker idWorker;
    @Qualifier("AuthServiceImpl")
    @Autowired
    private AuthService authService;
    @Autowired
    private RedisTemplate redisTemplate;

    @Qualifier("UserServiceImpl")
    @Autowired
    private UserService userService;

    @Autowired
    private MailClient mailClient;

    /**
     * 发送注册验证码
     * @param email
     * @return
     */
    @PostMapping("/sendCode/{email}")
    public ResponseResult sendEmailCodeAndRegister(@PathVariable String email){

        User one = userService.selectByEmail(email);
        if(one!=null)return ResponseResult.fail("该邮箱已被注册");
        String code = MyUtils.getEmailCode();
        redisTemplate.opsForValue().set("emailCode_"+email,code,5,TimeUnit.MINUTES);
        mailClient.sendMail(email,"Online Judge 注册邮箱","欢迎使用OnlineJudge，验证码为："+code+"。\n此验证码有效期为 5 分钟。如果已过期，请尝试请求向您发送新的确认电子邮件。");
        return ResponseResult.success();
    }

    /**
     * 发送验证码
     * @param email
     * @return
     */
    @PutMapping("/sendCode/{email}")
    public ResponseResult sendEmailCode(@PathVariable String email){
        User one = userService.selectByEmail(email);
        if(one==null)return ResponseResult.fail("该邮箱不存在");
        String code = MyUtils.getEmailCode();
        redisTemplate.opsForValue().set("emailCode_"+email,code,5,TimeUnit.MINUTES);
        mailClient.sendMail(email,"Online Judge 验证邮件","你好，"+one.getUsername()+"\n你正在进行安全验证，你的验证码为："+code+"。\n此验证码有效期为 5 分钟。如果已过期，请尝试请求向您发送新的确认电子邮件。");
        return ResponseResult.success();
    }

    /**
     * 修改密码 默认为123456
     * @param password
     * @param code
     * @param email
     * @return
     */
    @PostMapping("/setPassword")
    public ResponseResult setPassword( String password,@RequestParam String code,@RequestParam String email){
        Object o = redisTemplate.opsForValue().get("emailCode_" + email);
        if(o==null){
            return ResponseResult.fail("验证码已过期或不存在");
        }
        if(!code.equals(o.toString())){
            return ResponseResult.fail("验证码错误");
        }
        if(MyUtils.isEmpty(password))password = "123456";
        User user = userService.selectByEmail(email);
        user.setPassword(password);
        userService.updateById(user);

        return ResponseResult.success();
    }

    /**
     *
     * @param mp {oldEmail:老邮箱, oldCode=老邮箱验证码, newEmail：新邮箱, newCode=新邮箱验证码}
     * @return
     */
    @PostMapping("/setEmail")
    @AuthAnnotation({Auth.CLIENT})
    public ResponseResult setEmail(@RequestBody Map<String,String> mp){
        int i = this.equalsEmail(mp.get("oldEmail"), mp.get("oldCode"));
        int j = this.equalsEmail(mp.get("newEmail"), mp.get("newCode"));
        if(i==0&&j==0){
            User user = userService.selectByEmail(mp.get("oldEmail"));
            if(user==null)return ResponseResult.fail("该邮箱不存在");
            if (userService.selectByEmail(mp.get("newEmail"))!=null) {  //新邮箱
                return ResponseResult.fail("新邮箱已被注册");
            }
            user.setEmail(mp.get("newEmail"));
            userService.updateById(user);
        }
        else if(i==1)return ResponseResult.fail("邮箱验证码不正确");
        else if(i==2)return ResponseResult.fail("验证码已过期或不存在");
        else if(j==1)return ResponseResult.fail("新邮箱验证码不正确");
        else if(j==2)return ResponseResult.fail("新验证码已过期或不存在");
        return ResponseResult.success();
    }
    //注册
    @PostMapping("/register/{code}")
    public ResponseResult register(@PathVariable String code,@RequestBody User user,HttpServletRequest request){
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("username",user.getUsername());  //查重用户名
        if(MyUtils.isNotEmpty(user.getEmail()))
            userQueryWrapper.or().eq("email",user.getEmail());          //查重email
        if(MyUtils.isNotEmpty(user.getPhone()))
            userQueryWrapper.or().eq("phone",user.getPhone());          //查重phone

        //取出已存在的信息
        User one = userService.getOne(userQueryWrapper);
        if(one!=null){
            if(one.getUsername().equals(user.getUsername())){
                return ResponseResult.fail("用户名已存在");
            }
            if(MyUtils.isNotEmpty(one.getEmail())&&one.getEmail().equals(user.getEmail())){
                return ResponseResult.fail("邮箱已存在");
            }
            if(MyUtils.isNotEmpty(one.getPhone())&&one.getPhone().equals(user.getPhone())){
                return ResponseResult.fail("手机号已存在");
            }
        }
        Object o = redisTemplate.opsForValue().get("emailCode_" + user.getEmail());
        if(o==null){
            return ResponseResult.fail("验证码已过期或不存在");
        }
        if(!code.equals(o.toString())){
            return ResponseResult.fail("验证码错误");
        }
//        user.setId(idWorker.nextId().toString());
        request.setAttribute("loginUser",user);
        userController.save(user,request);
        return ResponseResult.success();
    }
    @PostMapping("/login")
    public ResponseResult login(@RequestParam String username, @RequestParam String password, HttpServletRequest request){
        //该用户登录失败的次数
        Integer logined = (Integer) redisTemplate.opsForValue().get(username);
        if(logined==null)logined = 0;
        if(logined>50){
            return ResponseResult.fail("该账号登录失败太多次,禁止登录24小时");
        }
        if(MyUtils.isEmpty(username)||MyUtils.isEmpty(password)){
            return ResponseResult.fail("用户名或密码不能为空");
        }
        QueryWrapper<User> queryWap = new QueryWrapper<>();
        queryWap.eq("username",username).or().eq("email",username).or().eq("phone",username);
        List<User> list = userService.list(queryWap);
        if (list==null||list.size()==0) {
            return ResponseResult.fail("用户名不存在");
        }
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        for (User user : list) {
            if (encoder.matches(password,user.getPassword())) { //密码正确
                if(user.getStatus()==1)return ResponseResult.fail("该账号不可用");
                //获取用户权限
                List<Auth> auths = authService.listByUserId(user.getId(),null,false);
                user.setAuths(auths);
                String token = encoder.encode(user.getId());
                user.setPassword(null);
                redisTemplate.opsForValue().set(token, JSON.toJSONString(user),30,TimeUnit.DAYS);
                //记录登录信息
                Session session = new Session(idWorker.nextId().toString(), user.getId(), request.getLocalAddr(), null, new Date(),MyUtils.getIp(request.getLocalAddr()));
                sessionService.save(session);
                return ResponseResult.success().setData(token);
            }
        }
        //失败次数+1
        redisTemplate.opsForValue().set(username,logined+1,1, TimeUnit.DAYS);
        return ResponseResult.fail("密码错误");
    }
    @PostMapping("/token")
    public ResponseResult getUser(@RequestParam String token){
        Object o1 = redisTemplate.opsForValue().get(token);
        User o = null;
        if(o1!=null) o = JSON.parseObject(((String) o1),User.class);
        return ResponseResult.success().setData(o);
    }

    /**
     * 验证邮箱验证码是否正确
     * @param email
     * @param code
     * @return 0正确 1错误 2验证码过期
     */
    private int equalsEmail(String email,String code){
        Object o = redisTemplate.opsForValue().get("emailCode_" + email);
        if(o==null){
            return 2;
        }
        if(!code.equals(o.toString())){
            return 1;
        }
        return 0;
    }
}
